package cn.com.nes.site.service.workOrder.impl;

import cn.com.nes.common.exception.BusinessException;
import cn.com.nes.mybatis.callcenter.entity.WorkOrderInfo;
import cn.com.nes.site.entity.bo.workorder.AsyncDistributeWorkOrderInstallBO;
import cn.com.nes.site.entity.bo.workorder.DistributeWorkOrderInstallBO;
import cn.com.nes.site.entity.vo.workOrder.BatchDistributeWorkOrderInstallVO;
import cn.com.nes.site.entity.vo.workOrder.TransferOrderInstallVo;
import cn.com.nes.site.handle.SendMessageHandler;
import cn.com.nes.site.service.crm.customer.CrmCustomerService;
import cn.com.nes.site.service.crm.customer.dto.CustomerDTO;
import cn.com.nes.site.service.crm.order.SaleOrderInfoService;
import cn.com.nes.site.service.crm.order.dto.SaleOrderInfoDTO;
import cn.com.nes.site.service.logs.ImportLogsService;
import cn.com.nes.site.service.system.user.SystemUserService;
import cn.com.nes.site.service.workOrder.AsyncDistributeWorkOrderInstallService;
import cn.com.nes.site.service.workOrder.WorkOrderService;
import cn.com.nes.site.service.workOrder.dto.AsyncDistributeWorkOrderInstallDTO;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 异步派发安装工单服务
 *
 * @Author: ShenWei
 * @Date: 2024/06/05/19:32
 */
@Service
@Slf4j
public class AsyncDistributeWorkOrderInstallServiceImpl implements AsyncDistributeWorkOrderInstallService {

    @Resource
    private WorkOrderService workOrderService;

    @Resource
    private SaleOrderInfoService saleOrderInfoService;

    @Resource
    private CrmCustomerService crmCustomerService;

    @Resource
    private ImportLogsService importLogsService;

    @Resource
    private SendMessageHandler sendMessageHandler;

    @Resource
    private SystemUserService systemUserService;

    /**
     * 异步派发安装工单
     */
    @Override
    public Map<String, Object> asyncDistributeWorkOrderInstall(BatchDistributeWorkOrderInstallVO vo) throws Exception {
        // 校验参数
        AsyncDistributeWorkOrderInstallBO bo = validateServiceUserAuth(vo);
        // 开始派单
        return distributeWorkOrderInstall(bo, getCustomerIdList(vo));
    }

    // 校验批量派单参数
    private AsyncDistributeWorkOrderInstallBO validateServiceUserAuth(BatchDistributeWorkOrderInstallVO vo) throws Exception {
        AsyncDistributeWorkOrderInstallBO bo = vo.convertToBo();
        // 校验入参
        if (CollectionUtil.isEmpty(bo.getCustomerIdList()) && StrUtil.isBlank(bo.getXzqhdm())) {
            throw new BusinessException("客户id列表和行政区划代码不能同时为空！");
        }

        // 校验是否可以派单
        DistributeWorkOrderInstallBO distributeWorkOrderInstallBo = new DistributeWorkOrderInstallBO();
        distributeWorkOrderInstallBo.setMaintainId(bo.getMaintainId());
        distributeWorkOrderInstallBo.setProjectId(bo.getProjectId());
        bo.setIsCaptain(workOrderService.validateServiceUserAuth(distributeWorkOrderInstallBo));
        bo.setProjectUuid(distributeWorkOrderInstallBo.getProjectUuid());
        return bo;
    }

    // 查询批量派单客户id
    public List<String> getCustomerIdList(BatchDistributeWorkOrderInstallVO vo){
        // 获取客户id List
        List<String> customerIdList = vo.getCustomerIdList();
        importLogsService.insertWorkOrderData(vo,customerIdList);
        List<String> customerIdListByAreaCode = crmCustomerService.getCustomerIdListByAreaCode(vo.getXzqhdm(), vo.getProjectId());
        customerIdList.addAll(customerIdListByAreaCode);
        customerIdList = customerIdList.stream().filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
        if (CollectionUtil.isEmpty(customerIdList)) {
            throw new BusinessException("本次批量派单未查询到任何符合条件的客户信息,派单失败");
        }
        return customerIdList;
    }

    // 开始派单
    private Map<String, Object> distributeWorkOrderInstall(AsyncDistributeWorkOrderInstallBO bo, List<String> customerIdList) throws Exception {
        // 收集系统单信息列表 & 工单id列表
        Set<Map<String, String>> preHandleInfoSet = new HashSet<>();
        // 根据客户id查询销售订单列表
        List<SaleOrderInfoDTO> saleOrderInfoList = saleOrderInfoService.getSaleOrderInfoListByCustomerId(customerIdList);
        if (CollectionUtil.isNotEmpty(saleOrderInfoList)) {
            saleOrderInfoList.stream()
                    .filter(n -> StrUtil.isNotBlank(n.getPriceMasterIds()) && CollectionUtil.isNotEmpty(Arrays.asList(n.getPriceMasterIds().split(","))))
                    .forEach(n -> {
                        List<String> priceMasterIdList = Arrays.asList(n.getPriceMasterIds().split(","));
                        preHandleInfoSet.addAll(priceMasterIdList.stream()
                                .map(priceMasterId -> {
                                    Map<String, String> map = new HashMap<>();
                                    map.put("distributeType", AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_NEW);
                                    map.put("saleOrderId", String.valueOf(n.getId()));
                                    map.put("priceMasterId", priceMasterId);
                                    map.put("customerId", n.getCustomerId());
                                    return map;
                                })
                                .collect(Collectors.toList()));
                    });
        }

        // 查询当前客户全部被拒单的工单id
        Set<WorkOrderInfo> workOrderInfoSet = workOrderService.getWorkOrderInfoSetByCustomerId(customerIdList, true);
        if (CollectionUtil.isNotEmpty(workOrderInfoSet)) {
            workOrderInfoSet.forEach(workOrderInfo -> {
                Map<String, String> map = new HashMap<>();
                map.put("distributeType", AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_OLD);
                map.put("workOrderId", String.valueOf(workOrderInfo.getId()));
                map.put("customerId", workOrderInfo.getCustomerId());
                preHandleInfoSet.add(map);
            });
        }

        // 创建一个客户池,避免重复查询客户信息
        Map<String, CustomerDTO> customerInfoMap = new HashMap<>();
        // 准备容器收集派单情况
        Set<AsyncDistributeWorkOrderInstallDTO> faultInfoSet = new HashSet<>();
        // 创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // 创建一个countDownLatch
        CountDownLatch countDownLatch = new CountDownLatch(preHandleInfoSet.size());
        // 开始派发工单
        for (Map<String, String> preHandleInfo : preHandleInfoSet) {
            executorService.execute(() -> {
                try {
                    if (AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_NEW.equals(preHandleInfo.get("distributeType"))) {
                        DistributeWorkOrderInstallBO distributeWorkOrderInstallBo = new DistributeWorkOrderInstallBO();
                        BeanUtils.copyProperties(bo, distributeWorkOrderInstallBo);
                        distributeWorkOrderInstallBo.setSaleOrderId(Long.valueOf(preHandleInfo.get("saleOrderId")));
                        distributeWorkOrderInstallBo.setPriceMasterId(Long.valueOf(preHandleInfo.get("priceMasterId")));
                        distributeWorkOrderInstallBo.setCustomerId(preHandleInfo.get("customerId"));
                        distributeWorkOrderInstallBo.setIsCaptain(bo.getIsCaptain());
                        distributeWorkOrderInstallBo.setProjectUuid(bo.getProjectUuid());

                        String workOrderId = workOrderService.distributeWorkOrderInstall(distributeWorkOrderInstallBo);
                        preHandleInfo.put("workOrderId", workOrderId);
                    } else if (AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_OLD.equals(preHandleInfo.get("distributeType"))) {
                        TransferOrderInstallVo transferOrderInstallVo = new TransferOrderInstallVo();
                        BeanUtils.copyProperties(bo, transferOrderInstallVo);
                        transferOrderInstallVo.setOrderId(Long.valueOf(preHandleInfo.get("workOrderId")));
                        transferOrderInstallVo.setMaintainId(bo.getMaintainId());
                        transferOrderInstallVo.setTransferDesc("批量重新派单给:");

                        workOrderService.transferOrderInstall(transferOrderInstallVo);
                    }
                    // 记录成功的派单情况
                    faultInfoSet.add(handleResult(preHandleInfo, customerInfoMap, null, AsyncDistributeWorkOrderInstallDTO.RET_CODE_SUCCESS));
                } catch (Exception e) {
                    // 记录失败的派单情况
                    faultInfoSet.add(handleResult(preHandleInfo, customerInfoMap, e.getMessage(), AsyncDistributeWorkOrderInstallDTO.RET_CODE_FAULT));
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();

        // 处理返回值
        return postHandle(faultInfoSet, bo);
    }

    // 处理派单失败返回信息
    private AsyncDistributeWorkOrderInstallDTO handleResult(Map<String, String> preHandleInfo, Map<String, CustomerDTO> customerInfoMap, String exceptionMessage, Integer retCode) {
        // 处理客户信息
        String customerId = preHandleInfo.get("customerId");
        CustomerDTO customerInfo = customerInfoMap.get(customerId);
        if (ObjectUtil.isNull(customerInfo)) {
            try {
                customerInfo = crmCustomerService.getCustomerById(customerId);
            } catch (Exception e) {
                log.info("这条没查到客户信息");
                customerInfo = new CustomerDTO();
                customerInfo.setUuid(customerId);
                customerInfo.setCustomerName(StrUtil.EMPTY);
            }
            customerInfoMap.put(customerId, customerInfo);
        }

        // 组装派单情况
        AsyncDistributeWorkOrderInstallDTO resultInfo = new AsyncDistributeWorkOrderInstallDTO();
        resultInfo.setRetCode(retCode);
        resultInfo.setCustomerId(customerId);
        resultInfo.setCustomerName(customerInfo.getCustomerName());
        resultInfo.setFaultMessage(exceptionMessage);
        resultInfo.setWorkOrderId(Long.valueOf(preHandleInfo.get("workOrderId")));
        if (AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_NEW.equals(preHandleInfo.get("distributeType"))) {
            resultInfo.setPriceMasterId(Long.valueOf(preHandleInfo.get("priceMasterId")));
            resultInfo.setDistributeType("派发新的工单");
        } else if (AsyncDistributeWorkOrderInstallDTO.DISTRIBUTE_TYPE_OLD.equals(preHandleInfo.get("distributeType"))) {
            resultInfo.setDistributeType("重新派发被拒单的工单");
        }
        return resultInfo;
    }

    // 解析返回值
    public Map<String, Object> postHandle(Set<AsyncDistributeWorkOrderInstallDTO> set, AsyncDistributeWorkOrderInstallBO bo) {
        Map<String, Object> map = new HashMap<>();
        map.put("faultCount", set.stream().filter(n -> AsyncDistributeWorkOrderInstallDTO.RET_CODE_FAULT.equals(n.getRetCode())).count());
        map.put("faultInfo", set.stream().filter(n -> AsyncDistributeWorkOrderInstallDTO.RET_CODE_FAULT.equals(n.getRetCode())).collect(Collectors.toSet()));
        map.put("successCount", set.stream().filter(n -> AsyncDistributeWorkOrderInstallDTO.RET_CODE_SUCCESS.equals(n.getRetCode())).count());
        map.put("successInfo", set.stream().filter(n -> AsyncDistributeWorkOrderInstallDTO.RET_CODE_SUCCESS.equals(n.getRetCode())).collect(Collectors.toSet()));
        map.put("totalCount", set.size());

        // 批量派发工单成功后给接单人发送通知
        try {
            String body = "您有" + map.get("successCount") + "个新的安装工单。";
            Long workOrderId = set.stream()
                    .filter(n -> AsyncDistributeWorkOrderInstallDTO.RET_CODE_SUCCESS.equals(n.getRetCode()))
                    .map(AsyncDistributeWorkOrderInstallDTO::getWorkOrderId)
                    .findFirst()
                    .orElse(null);

            Map<String, String> sendParams = new HashMap<>();
            sendParams.put("workOrderType", "install");
            sendParams.put("workOrderId", String.valueOf(workOrderId));
            sendParams.put("companyId", bo.getOperateUserCompanyId());
            sendMessageHandler.sendWorkOrderMessageToEasyRepair(null, body, systemUserService.getUserPhoneById(bo.getMaintainId()), sendParams);
        } catch (Exception e) {
            log.error("批量派单结束后发送通知消息失败,失败原因:{}", e.getMessage());
            e.printStackTrace();
        }
        return map;
    }
}
